// Copyright 2006 Mloofle Inc. All Rights Reserved.
import java.io.IOException;
import java.io.InputStream;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

/**
 * Answers whether a word is a stop word or a non-stop-word. Initializes and
 * tracks the set of stop words.
 */
public class WordAnalyzer {

  /**
   * Collects words output by a word lexer into a set.
   */
  private static final class WordCollector implements WordParser {

    /*
     * @see WordParser#endOfStream(int, int)
     */
    public void endOfStream(int totalBytes, int totalLines) {
      // nothing
    }

    /**
     * @return the result set of words that have been parsed
     */
    public Set getResults() {
      return resultSet;
    }

    /*
     * @see WordParser#processWord(java.lang.String)
     */
    public void processWord(String word, int lineNumber) {
      // canonicalize as lower case
      word = Util.toLowerCase(word);
      resultSet.add(word);
    }

    /**
     * The result set of words that have been parsed.
     */
    private final Set resultSet = new HashSet();
  }

  /**
   * Computes the set of stop words, based on the passed-in stop word input
   * stream. The input stream is parsed, and all contained words become members
   * of the returned set of stop words.
   * 
   * @param cAnalyzer a character analyzer which determines word boundaries
   * @param stopInputStream the input stream to read from
   * @return the set of stop words
   * @throws IOException if the stop input stream throws an exception
   */
  private static Set computeStopWords(CharacterAnalyzer cAnalyzer,
      InputStream stopInputStream) throws IOException {
    WordCollector collector = new WordCollector();
    new WordLexer(cAnalyzer).processInput(stopInputStream, collector);
    return collector.getResults();
  }

  /**
   * Constructs a word analyzer with an empty set of stop words.
   */
  public WordAnalyzer() {
    stopWordSet = Collections.EMPTY_SET;
  }

  /**
   * Constructs a word analyzer with the set of stop words contained in the
   * specified input stream.
   * 
   * @param cAnalyzer determines what a word is
   * @param stopInputStream the file to be read for stop words
   * @throws IOException if the stop input stream throws an exception
   */
  public WordAnalyzer(CharacterAnalyzer cAnalyzer, InputStream stopInputStream)
      throws IOException {
    stopWordSet = computeStopWords(cAnalyzer, stopInputStream);
  }

  /**
   * Determines whether or not the specified word is a stop word.
   * 
   * @param word a word which may be a stop word
   * @return <code>true</code> if the specified word is a stop word, otherwise
   *         <code>false</code>
   */
  public boolean isStopWord(String word) {
    word = Util.toLowerCase(word);
    return stopWordSet.contains(word);
  }

  /**
   * Returns the number of stop words; a hook for JUnit testing.
   * 
   * @return the number of stop words
   */
  int stopWordCount() {
    return stopWordSet.size();
  }

  /**
   * Stores the set of stop words.
   */
  private final Set stopWordSet;
}
